// 引入 OpenAI 通用 API 客户端
import OpenAI from 'openai';

// 创建 OpenAI 客户端
const LLMClient = new OpenAI({
    apiKey: "<替换为你的API Key>", 
    baseURL: "https://api.siliconflow.cn/v1"
});

// 请求大模型
const fetchLLM = async(messages,tools)=>{
    return await LLMClient.chat.completions.create({
        model: "Qwen/Qwen3-8B",//模型需要支持函数调用
        messages,// 传入消息列表
        temperature: 0.01,
        top_p: 0.95,
        stream: false,
        enable_thinking: false,
        tools// 传入工具列表信息
    });
}

// 定义加法工具函数
function addition(op) {
    return op.a + op.b;
}

// 定义工具函数列表
const tools = [
    {
        type: 'function',
        function: {
            name: 'addition',
            description: '对两个数字做求和计算，遇到提供两个数字求相加结果的问题优先使用本工具解决',
            parameters: {
                type: 'object',
                properties: {
                    a: {
                        type: 'int',
                        description: '第一个数字，例如 5',
                    },
                    b: {
                        type: 'int',
                        description: '第二个数字，例如 3.2',
                    },
                },
                required: ['a', 'b'],
            },
        }
    }
];

// 添加函数至映射对象
const functionMap = {
    addition
};

// 函数调用示例（content是用户的提问内容）
async function function_call_demo(content) {
    // 准备消息列表，用于存储对话历史
    let messages = [{ role: 'user', content }];

    console.log('第一轮提问信息:');
    console.log('用户提问内容:', messages);
    console.log('函数列表信息:\n',tools);

    // 首次调用大模型，根据“用户的提问内容”结合“可用工具函数列表信息”进行【意图识别】并【给出工具函数调用决策】）
    let response = await fetchLLM(messages, tools);

    console.log('【大模型回复】函数调用决策:\n', JSON.stringify(response.choices[0].message, null, 2));
    
    // 将工具函数调用的指引，添加到消息列表中-----------------------------------【关键节点1】
    messages.push(response.choices[0].message);

    // 检查是否有工具调用
    if (!response.choices[0].message.tool_calls || response.choices[0].message.tool_calls.length === 0) {
        // 如果没有工具调用，直接返回模型的回答
        return response.choices[0].message.content;
    }

    // 如果有工具调用，遍历所有的工具调用
    response.choices[0].message.tool_calls.forEach((toolCall) => {
        // 取出函数对象，函数名称：toolCall.function.name
        const func = functionMap[toolCall.function.name];
        // 调用函数对象，参数内容：toolCall.function.arguments（注意：这里的参数是一个JSON字符串，需要解析成对象。例如：{"a": 1, "b": 2}）
        const funcOut = func(JSON.parse(toolCall.function.arguments));
        console.log(`【外部系统执行】函数调用:函数名称:${toolCall.function.name},参数:${toolCall.function.arguments},结果:${funcOut}`);
        // 将工具函数调用的结果，添加到消息列表中--------------------------------【关键节点2】
        messages.push({
            role: 'tool',
            content: String(funcOut),
            tool_call_id: toolCall.id
        });
    })
    console.dir('|-----------------------------------两轮提问分割线-----------------------------------|');
    // 注意：这里的消息列表包含了用户输入、模型的回答以及工具函数调用的结果（仔细观察这个数据结果，可以帮你更好的理解LLM是如何进行function calling的）
    console.log('第二轮提问信息:\n', JSON.stringify(messages, null, 2));
    // 再次调用大模型，整合【用户原始问题】、【函数调用决策】及【函数调用结果】给出最终结果。
    response = await fetchLLM(messages);
    // 返回最终结果
    return response.choices[0].message.content;
}

// 使用 async/await 处理异步操作
async function main() {
    const result = await function_call_demo("1加3等于多少？");
    // 输出结果
    console.log('【大模型回复】最终结果:', result);
}

main().catch(console.error);